#include "game.hpp"
#include <thread>
#include <cstdlib>
#include <string>

namespace Tetris {

Game::Game()
    : m_currentPiece(nullptr)
    , m_nextPiece(nullptr)
    , m_gameOver(false)
    , m_gamePaused(false)
    , m_score(0)
    , m_level(1)
    , m_fallIntervalMs(INITIAL_FALL_INTERVAL_MS)
    , m_rng(std::chrono::system_clock::now().time_since_epoch().count()) // 使用当前时间作为随机种子
    , m_pieceDist(static_cast<int>(BlockType::I), static_cast<int>(BlockType::L)) // 范围从I到L
{
    setupNcurses();
    newGame();    
}


Game::~Game() {
    if (m_currentPiece != m_nextPiece) {
        delete m_currentPiece;
        delete m_nextPiece;
    }
    else {
        delete m_currentPiece;
    }
    teardownNcurses();
}


void Game::setupNcurses() {
    initscr();    // 初始化ncurses模式
    cbreak();    // 立即获取用户输入，无需回车
    noecho();    // 不在屏幕上显示用户输入
    keypad(stdscr, TRUE);    // 启用特殊键
    nodelay(stdscr, TRUE);    // getch() 非阻塞，防止卡住
    curs_set(0);    // 隐藏光标
    
    if (!has_colors()) {
        endwin();
        fprintf(stderr, "You terminal does not support colors!\n");
        exit(1);
    }
    start_color();
    initColors();

    // 创建子窗口
    // 游戏主板窗口(BOARD_HEIGHT + 2, BOARD_WIDTH * 2 + 2)
    m_gameWin = newwin(BOARD_HEIGHT - BOARD_HIDDEN_TOP + 2, BOARD_WIDTH * 2 + 2, 0, 0);
    // 下一个方块预览窗口（高度和宽度根据内容调整）
    m_nextPieceWin = newwin(6, 12, 0, BOARD_WIDTH * 2 + 3);
    // 分数信息窗口（高度和宽度根据内容调整）
    m_scoreWin = newwin(6, 12, 7, BOARD_WIDTH * 2 + 3);

    // 确保窗口能显示
    if (!m_gameWin || !m_nextPieceWin || !m_scoreWin) {
        endwin();
        fprintf(stderr, "Failed to create ncurses windows!\n");
        exit(1);
    }
}


void Game::initColors() {
    init_pair(COLOR_PAIR_I_BLOCK, COLOR_CYAN, COLOR_BLACK);
    init_pair(COLOR_PAIR_O_BLOCK, COLOR_YELLOW, COLOR_BLACK);
    init_pair(COLOR_PAIR_T_BLOCK, COLOR_MAGENTA, COLOR_BLACK);
    init_pair(COLOR_PAIR_S_BLOCK, COLOR_GREEN, COLOR_BLACK);
    init_pair(COLOR_PAIR_Z_BLOCK, COLOR_RED, COLOR_BLACK);
    init_pair(COLOR_PAIR_J_BLOCK, COLOR_BLUE, COLOR_BLACK);
    init_pair(COLOR_PAIR_L_BLOCK, COLOR_WHITE, COLOR_BLACK);
    init_pair(COLOR_PAIR_GHOST, COLOR_WHITE, COLOR_BLACK);
    init_pair(COLOR_PAIR_BORDER_TEXT, COLOR_WHITE, COLOR_BLACK);

    init_pair(COLOR_PAIR_EMPTY, COLOR_BLACK, COLOR_BLACK);
}


void Game::teardownNcurses() {
    delwin(m_gameWin);
    delwin(m_nextPieceWin);
    delwin(m_scoreWin);
    endwin();
}


void Game::newGame() {
    m_board.clear();
    delete m_currentPiece;
    delete m_nextPiece;
    m_currentPiece = nullptr;
    m_nextPiece = nullptr;

    m_score = 0;
    m_level = 1;
    m_fallIntervalMs = INITIAL_FALL_INTERVAL_MS;
    m_gameOver = false;
    m_gamePaused = false;

    generateNewPiece();
    m_lastFallTime = std::chrono::high_resolution_clock::now();
}


void Game::generateNewPiece() {
    // 删除当前方块前检查是否为下一个方块
    if (m_currentPiece != m_nextPiece) {
        delete m_currentPiece;
    }
    m_currentPiece = nullptr;

    if (m_nextPiece) {
        m_currentPiece = m_nextPiece;
        m_nextPiece = nullptr;
    } 
    if (!m_currentPiece) {
        // 第一次生成方块
        m_currentPiece = new Piece(static_cast<BlockType>(m_pieceDist(m_rng)));
    } 

    m_nextPiece = new Piece(static_cast<BlockType>(m_pieceDist(m_rng)));

    // 检查新生成的方块是否立即发生碰撞（游戏结束条件）
    if (m_board.isCollision(*m_currentPiece)) {
        m_gameOver = true;
    }
}


void Game::run() {

    bool restartRequested = false;

    do {
        restartRequested = false;
        while (!m_gameOver) {
            handleInput(getch());
            if (m_gamePaused) {
                render();
                std::this_thread::sleep_for(std::chrono::milliseconds(GAME_TICK_RATE_MS));
                continue;  
            }

            updateLogic();
            render();  // 渲染画面

        // 控制游戏循环的帧率
            std::this_thread::sleep_for(std::chrono::milliseconds(GAME_TICK_RATE_MS));
        }

        // 游戏结束画面
        werase(m_gameWin);
        werase(m_nextPieceWin);
        werase(m_scoreWin);

        mvwprintw(stdscr, LINES / 2 - 2, COLS / 2 - 5, "GAME OVER!");
        mvwprintw(stdscr, LINES / 2, COLS / 2 - 10, "Final Score: %ld", m_score);
        mvwprintw(stdscr, LINES / 2 + 2, COLS / 15, "Press 'q' to quit or 'r' to restart.");
        wrefresh(stdscr);

        // 等待用户输入‘q’ 或 ‘r’
        int ch;
        while ((ch = getch()) != 'q') {
            if (ch == 'q') return;
            if (ch == 'r') {
                newGame();
                restartRequested = true;
                break;
            }
            std::this_thread::sleep_for(std::chrono::milliseconds(GAME_TICK_RATE_MS));
        } 
    } while (restartRequested); 
}


void Game::handleInput(int ch) {
    if (ch == 'q') {
        m_gameOver = true;
        return;
    }
    // 暂停/恢复
    if (ch == 'p' || ch == 'P') {
        m_gamePaused = !m_gamePaused;
        return;
    }
    // 暂停期间忽略其他输入
    if (m_gamePaused) return;

    if (!m_currentPiece) return;

    // 复制当前状态，用于尝试移动/旋转后的碰撞检测
    Piece tempPiece = *m_currentPiece;
    bool moved = false;

    switch(ch) {
        case KEY_LEFT:
            tempPiece.move(-1, 0);
            if (!m_board.isCollision(tempPiece)) {
                m_currentPiece->move(-1, 0);
                moved = true;
            }
            break;;
        case KEY_RIGHT:
            tempPiece.move(1, 0);
            if (!m_board.isCollision(tempPiece)) {
                m_currentPiece->move(1, 0);
            }
            break;
        case KEY_UP: // 旋转
            tempPiece.rotate();
            if (!m_board.isCollision(tempPiece)) {
                m_currentPiece->rotate();
                moved = true;
            }
            else {
                // 如果这部分旋转后发生碰撞，尝试踢墙算法
                tempPiece.unrotate(); // 失败回调
            }
            break;
        case KEY_DOWN: // 软下落
            tempPiece.move(0, 1);
            if (!m_board.isCollision(tempPiece)) {
                m_currentPiece->move(0, 1);
                m_score += 1;
                moved = true;
                // 立即更新下落时间，加快下次自动下落
                m_lastFallTime = std::chrono::high_resolution_clock::now();
            }
            else {
                // 不能下落，固定方块
                m_board.mergePiece(*m_currentPiece);
                int clearedLines = m_board.clearLines();
                switch(clearedLines) {
                    case 1: m_score += SCORE_SINGLE_LINE; break;
                    case 2: m_score += SCORE_DOUBLE_LINE; break;
                    case 3: m_score += SCORE_TRIPLE_LINE; break;
                    case 4: m_score += SCORE_TETRIS_LINE; break;
                }
                if (clearedLines > 0) {
                    m_level = 1 + m_score / 1000;
                    m_fallIntervalMs = INITIAL_FALL_INTERVAL_MS - (m_level - 1) * 50;
                    if (m_fallIntervalMs < 100) m_fallIntervalMs = 100;
                }
                generateNewPiece();
            }
            break;
        case ' ': // 硬下落
            if (!m_currentPiece) break;

            Piece ghostPieceForHardDrop = *m_currentPiece;

            int scoreAddedByHardDrop = 0;

            while (!m_board.isCollision(ghostPieceForHardDrop)) {
                ghostPieceForHardDrop.move(0, 1);
            }
            // 最终会碰撞，回退一步到最终位置
            ghostPieceForHardDrop.move(0, -1);

            // 按距离加分
            scoreAddedByHardDrop = (ghostPieceForHardDrop.getPosition().y - m_currentPiece->getPosition().y) * 2;
            m_score += scoreAddedByHardDrop;
            
            // 直接跳到目标
            m_currentPiece->move(0, ghostPieceForHardDrop.getPosition().y - m_currentPiece->getPosition().y);

            m_board.mergePiece(*m_currentPiece);
            int clearedLines = m_board.clearLines();


            switch (clearedLines) {
                case 1: m_score += SCORE_SINGLE_LINE; break;
                case 2: m_score += SCORE_DOUBLE_LINE; break;
                case 3: m_score += SCORE_TRIPLE_LINE; break;
                case 4: m_score += SCORE_TETRIS_LINE; break;   
            }
            if (clearedLines > 0) {
                m_level = 1 + m_score / 1000;
                m_fallIntervalMs = INITIAL_FALL_INTERVAL_MS - (m_level - 1) * 50;
                if (m_fallIntervalMs < 100) m_fallIntervalMs = 100;
            }
            generateNewPiece();
            m_lastFallTime = std::chrono::high_resolution_clock::now();
            break;
        
        // 更多按键待添加
    } 
}


void Game::updateLogic() {
    auto currentTime = std::chrono::high_resolution_clock::now();
    long elapseMs = std::chrono::duration_cast<std::chrono::milliseconds>(currentTime - m_lastFallTime).count();

    if (elapseMs >= m_fallIntervalMs) {
        if (m_currentPiece) {
            Piece tempPiece = *m_currentPiece;
            tempPiece.move(0, 1);
            if (!m_board.isCollision(tempPiece)) {
                m_currentPiece->move(0, 1);
            }
            else {
                m_board.mergePiece(*m_currentPiece);
                int clearedLines = m_board.clearLines();
                 switch (clearedLines) {
                    case 1: m_score += SCORE_SINGLE_LINE; break;
                    case 2: m_score += SCORE_DOUBLE_LINE; break;
                    case 3: m_score += SCORE_TRIPLE_LINE; break;
                    case 4: m_score += SCORE_TETRIS_LINE; break;   
                }
                if (clearedLines > 0) {
                    m_level = 1 + m_score / 1000;
                    m_fallIntervalMs = INITIAL_FALL_INTERVAL_MS - (m_level - 1) * 50;
                    if (m_fallIntervalMs < 100) m_fallIntervalMs = 100;
                }
                generateNewPiece();  
            }
        }
        m_lastFallTime = currentTime;
    }
}

void Game::render() {
    werase(m_gameWin);
    werase(m_nextPieceWin);
    werase(m_scoreWin);

    m_board.draw(m_gameWin, 0, 0);

    if (m_currentPiece) {
        drawGhostPiece(m_gameWin, 0, 0);
        m_currentPiece->draw(m_gameWin, 0, 0);
    }

    drawNextPiece(m_nextPieceWin, 0, 0);
    drawScoreInfo(m_scoreWin, 0, 0);

    // 如果游戏暂停，显示暂停信息
    if (m_gamePaused) {
        mvwprintw(m_gameWin, (BOARD_HEIGHT - BOARD_HIDDEN_TOP) / 2, BOARD_WIDTH - 3, "PAUSE");
    }

    wrefresh(m_gameWin);
    wrefresh(m_nextPieceWin);
    wrefresh(m_scoreWin);
}


void Game::drawGhostPiece(WINDOW* win, int offset_x, int offset_y) {
    if (!m_currentPiece) return;

    Piece ghostPiece = *m_currentPiece;

    // 快速下落到最终位置
    while (!m_board.isCollision(ghostPiece)) {
        ghostPiece.move(0, 1);
    }
    ghostPiece.move(0, -1);
    ghostPiece.draw(win, offset_x, offset_y, true);
}

void Game::drawNextPiece(WINDOW* win, int offset_x, int offset_y) {
    box(win, 0, 0); // 绘制边框
    wattron(win, COLOR_PAIR(COLOR_PAIR_BORDER_TEXT));
    mvwprintw(win, 0, 1, "NEXT");
    wattroff(win, COLOR_PAIR(COLOR_PAIR_BORDER_TEXT));

    if (m_nextPiece) {
        m_nextPiece->draw(win, offset_x - 2, 1 + offset_y);
    }
}

void Game::drawScoreInfo(WINDOW* win, int offset_x, int offset_y) {
    box(win, 0, 0);
    wattron(win, COLOR_PAIR(COLOR_PAIR_BORDER_TEXT));
    mvwprintw(win, 0, 1, "INFO");
    mvwprintw(win, 2, 1, "Score %ld", m_score);
    mvwprintw(win, 3, 1, "Level: %d", m_level);
    wattroff(win, COLOR_PAIR(COLOR_PAIR_BORDER_TEXT));
}


} // namespace Tetris

